using System;
using System.Collections.Generic;
using System.Globalization;
using System.Reflection;
using System.Text;
using System.Windows.Forms;

namespace Normal
{
    /// <summary>
    /// The purpose of this class is to provide some helper functions
    /// to iterate with Windows Forms
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class WinFormHelper<T> where T : class
    {
        private string _dateFormat;

        protected string DateFormat
        {
            get { return _dateFormat; }
            set { _dateFormat = value; }
        }
        private string _numberFormat;

        protected string NumberFormat
        {
            get { return _numberFormat; }
            set { _numberFormat = value; }
        }
        
        /// <summary>
        /// Creates a WinFormHelper instance passing the DateFormat and NumberFormat Contants
        /// </summary>
        /// <param name="_dateFormat"></param>
        /// <param name="_numberFormat"></param>
        public WinFormHelper(string _dateFormat, string _numberFormat)
        {
            NumberFormat = _numberFormat;
            DateFormat = _dateFormat;
        }

        /// <summary>
        /// Creates a WinFormHelper instance passing the current CultureInfo
        /// </summary>
        /// <param name="ci"></param>
        public WinFormHelper(CultureInfo ci)
        {
            DateFormat = ci.DateTimeFormat.ShortDatePattern;
            NumberFormat = "F" + ci.NumberFormat.NumberDecimalDigits;
        }


        /// <summary>
        /// Fills the Windows Form with the given object
        /// </summary>
        /// <param name="_page">The Windows Form</param>
        /// <param name="UsedObject"></param>
        public void FillForm(Form _form, T UsedObject)
        {
            List<Control> lstControls = new List<Control>();
            GetElegibleFields(lstControls, _form.Controls);
            foreach (PropertyInfo Info in UsedObject.GetType().GetProperties())
            {
                foreach (object attr in Info.GetCustomAttributes(typeof(Id), true))
                {
                    foreach (Control control in lstControls)
                    {
                        if (Info.Name.Equals(control.Name, StringComparison.OrdinalIgnoreCase))
                        {
                            FillControl(control, UsedObject, Info.Name);
                        }
                    }
                }
                foreach (object attr in Info.GetCustomAttributes(typeof(Column), true))
                {
                    foreach (Control control in lstControls)
                    {
                        if (Info.Name.Equals(control.Name, StringComparison.OrdinalIgnoreCase))
                        {
                            FillControl(control, UsedObject, Info.Name);
                        }
                    }
                }
            }
        }

        /// <summary>
        /// Fill the Control based on Property Name and given Object
        /// </summary>
        /// <param name="control"></param>
        /// <param name="UsedObject"></param>
        /// <param name="PropertyName"></param>
        protected void FillControl(Control control, T UsedObject, string PropertyName)
        {
            String _value = GetFormattedValue(UsedObject.GetType().InvokeMember(PropertyName,
                BindingFlags.GetProperty, null, UsedObject, null));
            
            if (_value != null)
            {
                if (control is TextBox)
                {
                    ((TextBox)control).Text = _value;
                }
                else if (control is ComboBox)
                {
                    ((ComboBox)control).Text = _value;
                }
                else if (control is Label)
                {
                    ((Label)control).Text = _value;
                }
                else if (control is CheckBox)
                {
                    ((CheckBox)control).Checked = _value.Equals(Boolean.TrueString) || _value.Equals("S", StringComparison.OrdinalIgnoreCase)
                        || _value.Equals("Y", StringComparison.OrdinalIgnoreCase) || _value.Equals("1", StringComparison.OrdinalIgnoreCase);
                }
            }
        }

        /// <summary>
        /// Fill a new object based on Form Controls
        /// </summary>
        /// <param name="_page">The Page Context</param>
        /// <returns>New instance of the Object</returns>
        public T FillObject(Form _form)
        {
            T NewObject = Activator.CreateInstance<T>();
            return NewObject;
        }

        /// <summary>
        /// Get the elegible controls to be able to use to fill the properties
        /// </summary>
        /// <param name="lstControls">The list of controls to be filled</param>
        /// <param name="Controls">The Control Collection derived by page</param>
        protected void GetElegibleFields(List<Control> lstControls, Control.ControlCollection Controls)
        {
            foreach (Control control in Controls)
            {
                switch (control.GetType().ToString())
                {
                    case "System.Windows.Forms.Label":
                    case "System.Windows.Forms.TextBox":
                    case "System.Windows.Forms.ComboBox":
                    case "System.Windows.Forms.CheckBox":
                        lstControls.Add(control);
                        break;
                }
                GetElegibleFields(lstControls, control.Controls);
            }
        }

        /// <summary>
        /// Formats the value based on type and current cultureinfo
        /// </summary>
        /// <param name="_value"></param>
        /// <returns></returns>
        protected String GetFormattedValue(object _value)
        {
            if (_value is DateTime)
            {
                DateTime dt = DateTime.MinValue;
                if (DateTime.TryParse(Convert.ToString(_value), out dt))
                {
                    return dt.ToString(DateFormat);
                }
            }
            if (_value is Single)
            {
                float fl = 0;
                if (float.TryParse(Convert.ToString(_value), out fl))
                {
                    return fl.ToString(NumberFormat);
                }
            }
            if (_value is Double)
            {
                double dbl = 0;
                if (double.TryParse(Convert.ToString(_value), out dbl))
                {
                    return dbl.ToString(NumberFormat);
                }
            }
            if (_value is Decimal)
            {
                decimal dec = 0;
                if (decimal.TryParse(Convert.ToString(_value), out dec))
                {
                    return dec.ToString(NumberFormat);
                }
            }
            return Convert.ToString(_value);
        }
    }
}